﻿/*
 * LINQ to LDAP
 * http://linqtoldap.codeplex.com/
 * 
 * Copyright Alan Hatter (C) 2010-2012
 * alan.hatter@gmail.com - http://hattercoding.blogspot.com/
 * 
 * This project is subject to licensing restrictions. Visit http://linqtoldap.codeplex.com/license for more information.
 */

using System.Linq.Expressions;

namespace LinqToLdap.Visitors
{
    internal class BooleanReducer : ExpressionVisitor
    {
        private bool _requiresEvaluation = true;

        protected override Expression VisitBinary(BinaryExpression b)
        {
            if (b.NodeType == ExpressionType.OrElse)
            {
                if (b.Left.NodeType == ExpressionType.Constant && b.Left.Type == typeof(bool))
                {
                    _requiresEvaluation = true;
                    return Visit(true.Equals((b.Left as ConstantExpression).Value) ? b.Left : b.Right);
                }
                if (b.Right.NodeType == ExpressionType.Constant && b.Right.Type == typeof(bool))
                {
                    _requiresEvaluation = true;
                    return Visit(b.Left);
                }
            }
            if (b.NodeType == ExpressionType.AndAlso)
            {
                if (b.Left.NodeType == ExpressionType.Constant && b.Left.Type == typeof (bool))
                {
                    var value = (b.Left as ConstantExpression).Value;
                    if (false.Equals(value))
                    {
                        return Visit(b.Left);
                    }
                    if (true.Equals(value))
                    {
                        return Visit(b.Right);
                    }
                }
                else if (b.Right.NodeType == ExpressionType.Constant && b.Right.Type == typeof (bool))
                {
                    var value = (b.Right as ConstantExpression).Value;
                    if (false.Equals(value))
                    {
                        return Visit(b.Right);
                    }
                    if (true.Equals(value))
                    {
                        return Visit(b.Left);
                    }
                }
            }
            return base.VisitBinary(b);
        }

        public Expression Reduce(Expression expression)
        {
            Expression reduced = expression;
            while (_requiresEvaluation)
            {
                _requiresEvaluation = false;
                reduced = Visit(reduced);
            }

            return reduced;
        }
    }
}
